package org.log4jeditor.xml.editor;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.ArrayUtils;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentPartitioner;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.exceptions.ResourceAlreadyExists;
import org.eclipse.wst.sse.core.internal.provisional.exceptions.ResourceInUse;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.eclipse.wst.sse.ui.internal.StructuredTextViewer;
import org.eclipse.wst.xml.core.internal.text.rules.StructuredTextPartitionerForXML;
import org.junit.Assert;
import org.log4jconfig.xml.editor.Log4jXMLStructuredTextViewerConfiguration;

@SuppressWarnings("restriction")
public class WorkbenchTasks {

	public static IJavaProject createProject(IProject project,
			IProgressMonitor monitor) throws CoreException {
		monitor.beginTask("Creating " + project.getName(), 3);
		IProjectDescription description = ResourcesPlugin.getWorkspace()
				.newProjectDescription(project.getName());
		if (!project.exists()) {
			project.create(description, monitor);
		}
		if (!project.isOpen()) {
			project.open(monitor);
		}
		monitor.worked(1);
		// Setting Java Nature to the eclipse project
		String[] natures = description.getNatureIds();
		String[] newNatures = new String[natures.length + 1];
		System.arraycopy(natures, 0, newNatures, 0, natures.length);
		newNatures[natures.length] = JavaCore.NATURE_ID;
		description.setNatureIds(newNatures);
		if (!project.isOpen()) {
			project.open(monitor);
		}
		project.setDescription(description, monitor);
		monitor.worked(1);
		// Create Java Project
		IJavaProject javaProject = JavaCore.create(project);
		if (javaProject.exists() && !javaProject.isOpen()) {
			javaProject.open(monitor);
		}

		IFolder srcFolder = project.getFolder(new Path("src"));
		if (!srcFolder.exists()) {
			srcFolder.create(true, true, monitor);
		}

		IFolder outFolder = project.getFolder(new Path("bin"));
		if (!outFolder.exists()) {
			outFolder.create(true, true, monitor);
		}
		javaProject.setOutputLocation(outFolder.getFullPath(), monitor);

		Set<IClasspathEntry> entries = new HashSet<IClasspathEntry>();
		entries.add(JavaCore.newSourceEntry(srcFolder.getFullPath()));
		entries.add(JavaRuntime.getDefaultJREContainerEntry());
		
		javaProject.setRawClasspath(entries.toArray(new IClasspathEntry[entries
				.size()]), monitor);
		monitor.worked(1);

		return javaProject;
	}

	public static void removeSourceFolder(IProject project, IProgressMonitor progressMonitor)
			throws JavaModelException {
		IFolder srcFolder = project.getFolder(new Path("src"));
		IJavaProject javaProject = JavaCore.create(project);
		List<IClasspathEntry> entries = new ArrayList<IClasspathEntry>(Arrays
				.asList(javaProject.getRawClasspath()));
		IClasspathEntry srcEntry = JavaCore.newSourceEntry(srcFolder
				.getFullPath());
		for (Iterator<IClasspathEntry> entryIterator = entries.iterator(); entryIterator
				.hasNext();) {
			IClasspathEntry entry = entryIterator.next();
			if (entry.equals(srcEntry)) {
				entries.remove(entry);
			}
		}
		javaProject.setRawClasspath(entries.toArray(new IClasspathEntry[entries
				.size()]), progressMonitor);

	}

	public static void addJavaProjectLibrary(IJavaProject javaProject,
			IPath path, IProgressMonitor monitor) throws JavaModelException {
		Assert.assertTrue(
				"Following library does not exist or is not readable: "
						+ path.toFile(), path.toFile().exists()
						&& path.toFile().canRead());
		IClasspathEntry[] classpathEntries = javaProject.getRawClasspath();
		classpathEntries = (IClasspathEntry[]) ArrayUtils.add(classpathEntries,
				JavaCore.newLibraryEntry(path, null, null));
		javaProject.setRawClasspath(classpathEntries, monitor);
	}

	public static void removeJavaProjectLibrary(IJavaProject javaProject,
			IPath path, IProgressMonitor monitor) throws JavaModelException {
		IClasspathEntry[] classpathEntries = javaProject.getRawClasspath();
		int index = 0;
		for (IClasspathEntry entry : classpathEntries) {
			if (entry.getPath().toFile().getAbsolutePath().equals(
					path.toFile().getAbsolutePath())) {
				break;
			}
			index++;
		}
		classpathEntries = (IClasspathEntry[]) ArrayUtils.remove(
				classpathEntries, index);
		javaProject.setRawClasspath(classpathEntries, monitor);
	}

	public static IJavaProject createJavaProject(String projectName,
			File srcDir, IProgressMonitor monitor) throws Exception {
		// lookup log4j-xxx.jar
		// create and setup project
		IJavaProject javaProject = null;
		try {
			IWorkspace workspace = ResourcesPlugin.getWorkspace();
			IWorkspaceRoot root = workspace.getRoot();
			IProject project = root.getProject(projectName);
			monitor.beginTask("creating test project", 10);
			// create the project
			javaProject = WorkbenchTasks.createProject(project, monitor);
			String destinationProjectString = project.getLocation()
					.toOSString()
					+ File.separator + "src";
			File targetDir = new File(destinationProjectString);
			IOUtils.copyDir(srcDir, targetDir);
			project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
			project.build(IncrementalProjectBuilder.FULL_BUILD, monitor);
			monitor.worked(1);

			Assert.assertTrue(project.exists());
			Assert.assertTrue(javaProject.exists());

		} finally {
			if (monitor != null) {
				monitor.done();
			}
		}
		return javaProject;
	}

	public static ISourceViewer initializeSourceViewer(IDocument document) {
		// some test environments might not have a "real" display
		if (Display.getCurrent() != null) {
			Shell shell = null;
			Composite parent = null;
			if (PlatformUI.isWorkbenchRunning()) {
				shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
						.getShell();
			} else {
				shell = new Shell(Display.getCurrent());
			}
			parent = new Composite(shell, SWT.NONE);

			// dummy viewer
			StructuredTextViewer sourceViewer = new StructuredTextViewer(
					parent, null, null, false, SWT.NONE);
			// configure SourceViewer
			sourceViewer
					.configure(new Log4jXMLStructuredTextViewerConfiguration());
			sourceViewer.setDocument(document);
			return sourceViewer;
		} else {
			Assert
					.fail("Unable to run the test as a display must be available.");
			return null;
		}
	}

	/**
	 * @noreference This method is not intended to be referenced by clients.
	 */
	public static IStructuredDocument openFileForEdit(IFile file)
			throws ResourceAlreadyExists, ResourceInUse, IOException,
			CoreException {
		IStructuredModel model = StructuredModelManager.getModelManager()
				.getModelForEdit(file);
		model.reload(file.getContents());
		
		IStructuredDocument document = model.getStructuredDocument();
		IDocumentPartitioner partitioner = new StructuredTextPartitionerForXML();
		partitioner.connect(document);
		document.setDocumentPartitioner(partitioner);
		return document;
	}

	public static IFile getFile(String filePath) throws CoreException {
		IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(
				new Path(filePath));
		if (file != null && !file.exists()) {
			Assert.fail("Unable to locate " + file.getFullPath() + " file.");
		}
		file.refreshLocal(IResource.DEPTH_ONE, new NullProgressMonitor());
		return file;
	}

	public static void deleteAllMarkersOnFile(IFile file) throws CoreException {
		file.deleteMarkers(null, true,IResource.DEPTH_INFINITE) ;
	}
	
	public static void buildWorkspace(IProgressMonitor progressMonitor)
			throws CoreException {
		ResourcesPlugin.getWorkspace().build(
				IncrementalProjectBuilder.FULL_BUILD, progressMonitor);

	}
}
